/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author Administrator
 */
public class Rating {
    private ArrayList<Double> initialData;//待分级的原始数据
    private ArrayList<Double> BreakValue;//数据分级后，个区间的端点值
    private int rankNum;//分级数
    private rankTypeEnum type;//分级类型
    
    public Rating(ArrayList<Double> data,int rankNum,rankTypeEnum type)
    {
        initialData=data;
        this.rankNum=rankNum;
        this.type=type;
        this.BreakValue=new ArrayList<>();
    }
    
    public Rating(ArrayList<Double> initialData,ArrayList<Double> BreakValue,int rankNum,rankTypeEnum type){
        this.initialData=initialData;
        this.BreakValue=BreakValue;
        this.rankNum=rankNum;
        this.type=type;
    }
    
    public void setBreakValue(ArrayList<Double> BreakValue){
        this.BreakValue=BreakValue;
    }
    public ArrayList<Double> getBreakValue(){
        return this.BreakValue;
    }
    /**
     *
     * @return
     */
    public ArrayList ArithmeticRating()
    {
        ArrayList rating=new ArrayList<>();
        double maxval=initialData.get(0);
	double minval=initialData.get(0);
	for(int i=1;i<initialData.size();i++)
	{
            if(initialData.get(i)>maxval){
		maxval=initialData.get(i);
            }
            else if(initialData.get(i)<minval){
		minval=initialData.get(i);
            }	
	}
	double interval=(maxval-minval)/rankNum;
	for(int i=0;i<initialData.size();i++){
            int r=(int) ((initialData.get(i)-minval)/interval);
            rating.add(r);
	}
        return rating;
    }
    
    public ArrayList<Integer> getRatingResult(){
        ArrayList<Integer> Graduated=new ArrayList<>();
        if(BreakValue.isEmpty()){
            switch(type){
                case EqualInterval:
                    EqualInterval();
                    for (Iterator<Double> it = initialData.iterator(); it.hasNext();) {
                        double v = it.next();
                        int i=0;
                        for(i=1;i<BreakValue.size();i++){
                            if(v<BreakValue.get(i)&&v>=BreakValue.get(i-1)){
                            Graduated.add(i);
                            break;
                            }
                        }
                        if(i==BreakValue.size()){
                        Graduated.add(i-1);
                        }
                
                    }
                    break;
                case Quantile:
                    Qualtile();
                    for (Iterator<Double> it = initialData.iterator(); it.hasNext();) {
                        double v = it.next();
                        int i=0;
                        for(i=1;i<BreakValue.size();i++){
                            if(v<BreakValue.get(i)&&v>=BreakValue.get(i-1)){
                            Graduated.add(i);
                            break;
                            }
                        }
                        if(i==BreakValue.size()){
                        Graduated.add(i-1);
                        }
                
                    }
                    break;
                case NaturalBreaks:
                    NaturalBreaks();
                    rankNum-=1;
                    Collections.sort(BreakValue);
                    for (Iterator<Double> it = initialData.iterator(); it.hasNext();) {
                        double v = it.next();
                        int i=0;
                        if(v<BreakValue.get(i))
                        {
                            Graduated.add(i+1);
                        }
                        else
                        {
                            for(i=1;i<BreakValue.size();i++){
                                if(v<BreakValue.get(i)&&v>=BreakValue.get(i-1)){
                                    Graduated.add(i+1);
                                    break;
                                }
                            }
                            if(i==BreakValue.size()){
                                Graduated.add(i+1);
                            }
                        }
                
                    }
                    break;
            }
        }
        
        return Graduated;
    }
    //等差分级
    private void EqualInterval(){
        double maxval=initialData.get(0);
	double minval=initialData.get(0);
	for(int i=1;i<initialData.size();i++)
	{
            if(initialData.get(i)>maxval){
		maxval=initialData.get(i);
            }
            else if(initialData.get(i)<minval){
		minval=initialData.get(i);
            }	
	}
	double interval=(maxval-minval)/rankNum;
        for(int i=0;i<=rankNum;i++){
            BreakValue.add(minval+interval*i);
        }
    }
    //等个数分级
    private void Qualtile(){
        double interval=initialData.size()/rankNum;
        if(interval%1>0.5){
            interval=Math.ceil(interval);
        }
        else
        {
            interval=Math.floor(interval);
        }
        List<Double> dataCopy=initialData.subList(0, initialData.size()-1);
        Collections.sort(dataCopy);
        for(int i=0;i<rankNum;i++){
            BreakValue.add(dataCopy.get(i*(int)interval));
        }
        
    }
    //自然断点法分级
    private void NaturalBreaks(){
        int length=initialData.size();
       double[][] mat1 = new double[length + 1][rankNum + 1];
        double[][] mat2 = new double[length + 1][rankNum + 1];
        double[] st = new double[length];
        
        
        for (int i = 1; i <= rankNum; i++) {
            mat1[1][i] = 1;
            mat2[1][i] = 0;
            for (int j = 2; j <= length; j++)
                mat2[j][i] = Double.MAX_VALUE;
        }
        double v = 0;
        for (int l = 2; l <= length; l++) {
            double s1 = 0;
            double s2 = 0;
            double w = 0;
            for (int m = 1; m <= l; m++) {
                int i3 = l - m + 1;

                double val = initialData.get(i3 -1);
                
                
                s2 += val * val;
                s1 += val;
                
                
                w++;
                v = s2 - (s1 * s1) / w;
                int i4 = i3 - 1;
                if (i4 != 0) {
                    for (int j = 2; j <= rankNum; j++) {
                        if (mat2[l][j] >= (v + mat2[i4][j - 1])) {
                            mat1[l][j] = i3;
                            mat2[l][j] = v + mat2[i4][j - 1];

                        };
                    };
                };
            };
            mat1[l][1] = 1;
            mat2[l][1] = v;
        };
        int k = length;
        int[] kclass = new int[rankNum];
        kclass[rankNum - 1] = initialData.size() - 1;
        for (int j = rankNum; j >= 2; j--) {
            int id =  (int) (mat1[k][j]) - 2;
            kclass[j - 2] = id;
            k = (int) mat1[k][j] - 1;
        };
        
        for(int i=0;i<rankNum;i++){
            BreakValue.add(initialData.get(kclass[i]));
        }
    }
    
    
}
